/*************************************************************************
	> File Name: dasserver.cpp
	> Author: xuwenlong
	> Mail: myxuan475@126.com 
	> Created Time: 2018年09月17日 星期一 14时00分18秒
 ************************************************************************/

#include <iostream>
#include <sys/select.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <string.h>
#include <event.h>
#include <stdlib.h>
#include <event2/rpc.h>
#include <event2/listener.h>
#include <event2/thread.h>

#include "server.h"
#include <logger.h>

Server::Server():
    m_EvBase(NULL)
    ,m_EvconnListener(NULL),
    m_pThread(threads::CreateThread("server",this)),
    m_pEvent(NULL)

{
}

Server::~Server()
{
    StopServer();
    threads::DeleteThread(m_pThread);
    m_EvconnListener = NULL;
    m_EvBase = NULL;
}

void Server::threadMain()
{
    evthread_use_pthreads();
    m_EvBase = event_base_new();

    evthread_make_base_notifiable(m_EvBase);

    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(m_iPort);
//    sin.sin_addr = INADDR_ANY;
    m_EvconnListener = evconnlistener_new_bind(
                m_EvBase,
                DoAccept,
                (void*)this,
                LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_THREADSAFE,
                512,
                (struct sockaddr*)&sin, sizeof(sin));
    if (m_EvconnListener == NULL)
    {
        return;
    }
    struct timeval timeout = {5, 0};

    m_pEvent = event_new(
                m_EvBase,
                -1,
                EV_TIMEOUT|EV_PERSIST,
                timeout_event,this);
    event_add(m_pEvent, &timeout);

    event_base_dispatch(m_EvBase);
}

void Server::timeout_event(evutil_socket_t fd, short ev, void *arg)
{
//    server_event(NULL,EV_TIMEOUT,arg);
    Server *client = static_cast<Server*>(arg);
    client->TimeOutEvent(fd,ev);
}

bool Server::StartServer(const int port)
{
    LOG_TRACE();
    if (m_pThread->is_running() && m_iPort == port)
        return true;

    m_iPort = port;
    StopServer();
    return m_pThread->start();
}

tUser Server::CreateWork()
{
    tUser pWork = CreateUser();
    AddUser(pWork);
    return pWork;
}

void Server::AcceptWork(int fd,sockaddr *addr)
{
    tUser pWork = CreateWork();

    pWork->startWork(fd,addr);
}

void Server::DoAccept(evconnlistener *listener, int fd, sockaddr *sa, int socklen, void *user_data)
{
    Server* pServer = static_cast<Server *>(user_data);

    sockaddr_in *addr_in = (sockaddr_in*)sa;
    LOG_INFO("new client  %s:%d",inet_ntoa(addr_in->sin_addr),
             addr_in->sin_port);
    pServer->AcceptWork(fd,sa);
}

tUser Server::CreateUser()
{
    return new User(this,new ProtocolHandler(
                        ProtocolHandler::HAS_TOKEN));
}

void Server::ClearUsers()
{
    AutoLock lock(m_lock);
    m_list.clear();
}

void Server::AddUser(tUser user)
{
    AutoLock lock(m_lock);
    m_list.push_back(user);
}

void Server::TimeOutEvent(int fd, short ev)
{
    AutoLock lock(m_lock);
    vector<tUser>::iterator iter;
    for (iter = m_list.begin();iter != m_list.end();) {
        tUser work = *iter;
        if (!work.valid()) {
            iter = m_list.erase(iter);
        }
        else if (work->IsTaskExit()) {
            iter = m_list.erase(iter);
        }
        else {
            iter++;
        }
    }
}


void Server::StopServer()
{
    ClearUsers();

    if (m_pEvent) {
        event_del(m_pEvent);
        event_free(m_pEvent);
        m_pEvent = NULL;
    }

    if (m_EvconnListener) {
        evconnlistener_free(m_EvconnListener);
        m_EvconnListener = NULL;
    }
    if (m_EvBase) {
        //        struct timeval delay = { 5, 0 };
        event_base_loopexit(m_EvBase,NULL);
        event_base_free(m_EvBase);
        m_EvBase = NULL;
    }
    m_pThread->join();
}
